package PAP;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;

import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.vocabulary.RDFS;

public class SplitOntologySnomedNci {

	public static void main(String[] args) {
		try {
			OWLOntology source = readOWL("src/ontologies/human.owl");
			// OWLOntology source =
			// matching.readOWL("src/ontologies/UnivCsCMO.owl");
			OWLOntology target = readOWL("src/ontologies/OpenGalen.owl");
			
			//ONTOLOGIA HUMAN
			System.out.println("Human");
			System.out.println("Tamanho orig: " + source.getClassesInSignature().size());
			ArrayList<String> targetS = getClassesToNewOntology(calculateFathersHuman(source), source, 1);
			System.out.println("Num. Classes: " + targetS.size());
			removeClasses(targetS, "src/ontologies/human.owl", "src/ontologies/human_sub.owl");
			OWLOntology newSource = readOWL("src/ontologies/human_sub.owl");
			System.out.println("Tamanho Mod: " + newSource.getClassesInSignature().size());
			
			//ONTOLOGIA MOUSE
			System.out.println("Galen");
			System.out.println("Tamanho orig: " + target.getClassesInSignature().size());
			ArrayList<String> targetF = getClassesToNewOntology(calculateFathersGalen(target), target, 2);
			System.out.println("Num. Classes: " + targetF.size());
			removeClasses(targetF, "src/ontologies/OpenGalen.owl", "src/ontologies/OpenGalen_sub.owl");
			OWLOntology newTarget = readOWL("src/ontologies/OpenGalen_sub.owl");
			System.out.println("Tamanho Mod: " + newTarget.getClassesInSignature().size());
			
			//newAlignmentReference(newSource, newTarget, "src/ontologies/reference_human_mouse.rdf", "src/ontologies/reference_human_mouse_SUB.txt");

			// Set<OWLClass> listClassSource = source.getClassesInSignature();
			// //System.out.println(listClassSource.size());
			//
			// Set<OWLClass> listClassTarget = target.getClassesInSignature();
			// //System.out.println(listClassTarget.size());
			//
			// ArrayList<String> todasCombinacoes = new ArrayList<String>();
			// for (OWLClass src : listClassSource) {
			// for (OWLClass tgt : listClassTarget) {
			// todasCombinacoes.add(src.getIRI().getFragment() + " - " +
			// tgt.getIRI().getFragment());
			// }
			// }
			//
			// ArrayList<String> reference =
			// ReaderRDF.alignmentForOAEIOntology("src/ontologies/reference_huma_mouse.rdf");
			//
			// reference.retainAll(todasCombinacoes);
			//
			// System.out.println(reference.size());
			// ArrayList<String> gab = new ArrayList<String>();
			//
			// for (String string : reference) {
			// if(todasCombinacoes.contains(string)){
			// gab.add(string);
			// }
			// }

			// System.out.println(gab.size());

		} catch (OWLOntologyCreationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private static void newAlignmentReference(OWLOntology newSource,
			OWLOntology newTarget, String pathAlignment, String outputFileName) {
		//All Combinations
		ArrayList<String> combinations = new ArrayList<String>();
		for (OWLClass cSource : newSource.getClassesInSignature()) {
			for (OWLClass cTarget : newTarget.getClassesInSignature()) {
				combinations.add(cSource.getIRI().getFragment() + " - " + cTarget.getIRI().getFragment());
			}
		}
		
		ArrayList<String> alignReferece = ReaderRDF.alignmentForOAEIOntology(pathAlignment);
		ArrayList<String> result = new ArrayList<String>();
		for (String string : alignReferece) {
			if (combinations.contains(string)) {
				result.add(string);
			}
		}
		//alignReferece.retainAll(combinations);
		
		
		try {
			OutputStream os = new FileOutputStream(outputFileName);
			for (String string : result) {
				string = string + "\n";
				os.write(string.getBytes());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		ArrayList<String> newAlignReferece = ReaderRDF.alignmentReadyForOntology(outputFileName);
		System.out.println("Alinhamentos: " + newAlignReferece.size());
		
//		for (String string : newAlignReferece) {
//			System.out.println(string);
//		}
		
	}
	
	public static ArrayList<String> alignmentForOAEIOntology(String path){
		File f = new File(path);
		FileReader fr;
		ArrayList<String> alignRDF = new ArrayList<String>();
		try {
			fr = new FileReader(f);
			Model model = ModelFactory.createDefaultModel();
			model.read(fr, RDFS.getURI());

			StmtIterator iter = model.listStatements();
			boolean flag = false;
			String align = "";
			while (iter.hasNext()) {
				Statement stmt = iter.next();
				// System.out.println(stmt);
				// Now use <stmt>
				if (stmt.getObject().toString().equals("=")){
					flag = true;
				} 
				if(stmt.getPredicate().getLocalName().equals("alignmententity2") && flag){
					align += stmt.getObject().asResource().getLocalName();
				}
				
				if(stmt.getPredicate().getLocalName().equals("alignmententity1") && flag){
					align += (" - " + stmt.getObject().asResource().getLocalName());
					alignRDF.add(align);
					align = "";
					flag = false;
				}
			}
			

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return alignRDF;
	}

	private static ArrayList<String> getClassesToNewOntology(
			List<OWLClass> calculateFathers, OWLOntology ontology, int numberFather) {
		ArrayList<String> listOfClasses = new ArrayList<String>();
		for (OWLClass owlClass : calculateFathers) {
			//System.out.println(getLabel(owlClass.getAnnotations(ontology)));
			//getLabel(owlClass, ontology);
			listOfClasses.add(owlClass.getIRI().getFragment());
		}
		
		ArrayList<OWLClass> aux = new ArrayList<OWLClass>();
		int count = 0;
		for (int i = 0; i < calculateFathers.size(); i++) {
			if (calculateFathers.size() == 0) {
				break;
			}
			for (OWLClassExpression cls : calculateFathers.get(i).getSubClasses(ontology)) {
				//System.out.println(cls.asOWLClass().getSuperClasses(ontology).size());
				if(cls.asOWLClass().getSuperClasses(ontology).size() <= numberFather){
					listOfClasses.add(cls.asOWLClass().getIRI().getFragment());
					aux.add(cls.asOWLClass());
				}
			}
			if (aux.contains(calculateFathers.get(i))) {
				aux.remove(calculateFathers.get(i));
			}
			if(i == calculateFathers.size()-1){
				calculateFathers = aux;
			}
			//Algoritmo pra diminuir o tamanho da ontologia
//			count++;
//			if (count > 2) {
//				break;
//			}
		}
		return listOfClasses;
	}

	private static void removeClasses(ArrayList<String> targetF,
			String inputFileName, String outputFileName) {
		try {
			// create the reasoning model using the base
			OntModel inf = ModelFactory.createOntologyModel();

			// use the FileManager to find the input file
			InputStream in = FileManager.get().open(inputFileName);
			if (in == null) {
				throw new IllegalArgumentException("File: " + inputFileName
						+ " not found");
			}

			inf.read(in, "");
			
			List<Statement> stmts = inf.listStatements().toList();
			for (Statement statement : stmts) {
				if (statement.getPredicate() != null && statement.getPredicate().toString().equalsIgnoreCase("http://www.w3.org/2000/01/rdf-schema#subClassOf") && statement.getResource().getLocalName() == null) {
					inf.remove(statement);
					//System.out.println(statement.getResource().getLocalName());
				}
				
				if (statement.getSubject().isResource() /*&& statement.getSubject().getLocalName() != null && !statement.getSubject().getLocalName().equals("Restriction") */&& !targetF.contains(statement.getSubject().getLocalName())) {
					//System.out.println(statement.getSubject().getLocalName() + " - " + statement.getSubject());
					inf.remove(statement);
				}
			}
			
			OutputStream os = new FileOutputStream(outputFileName);
			inf.write(os);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

	/**
	 * Method to read owl file.
	 * 
	 * @param path
	 * @return OWL Ontology
	 * @throws OWLOntologyCreationException
	 */
	public static OWLOntology readOWL(String path)
			throws OWLOntologyCreationException {
		String DOCUMENT_IRI = path;
		File file = new File(DOCUMENT_IRI);
		// Create our ontology manager in the usual way.
		OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
		// Load a copy of the people+pets ontology. We'll load the ontology from
		// the web (it's acutally located in the TONES ontology repository).
		IRI docIRI = IRI.create(file);
		// We load the ontology from a document - our IRI points to it directly
		OWLOntology ontology = manager.loadOntologyFromOntologyDocument(docIRI);

		return ontology;
	}

//	private static List<OWLClass> calculateFathersMouse(OWLOntology onto) {
//		Set<OWLClass> listClass = onto.getClassesInSignature();
//		ArrayList<OWLClass> fathers = new ArrayList<OWLClass>();
//		for (OWLClass src : listClass) {
//			ArrayList<OWLClassExpression> superClasses = new ArrayList<OWLClassExpression>(src.getSuperClasses(onto));
//			ArrayList<OWLClassExpression> subClasses = new ArrayList<OWLClassExpression>(src.getSubClasses(onto));
//			if (!superClasses.isEmpty() && superClasses.get(0).asOWLClass().getIRI().getFragment().equalsIgnoreCase("Thing") && !subClasses.isEmpty()) {
//				fathers.add(src);
//			}
//		}
//		//total 151 pais
//		System.out.println(fathers.size());
//		return fathers.subList(0,20);
//
//	}
	
	
	private static List<OWLClass> calculateFathersHuman(OWLOntology onto) {
		Set<OWLClass> listClass = onto.getClassesInSignature();
		ArrayList<OWLClass> fathers = new ArrayList<OWLClass>();
		for (OWLClass src : listClass) {
			ArrayList<OWLClassExpression> superClasses = new ArrayList<OWLClassExpression>(src.getSuperClasses(onto));
			ArrayList<OWLClassExpression> subClasses = new ArrayList<OWLClassExpression>(src.getSubClasses(onto));
			if (superClasses.isEmpty() && !subClasses.isEmpty()) {
				fathers.add(src);
			}
		}
		//System.out.println(fathers.size());
		return fathers.subList(0,1);

	}
	
	private static List<OWLClass> calculateFathersGalen(OWLOntology onto) {
		Set<OWLClass> listClass = onto.getClassesInSignature();
		ArrayList<OWLClass> fathers = new ArrayList<OWLClass>();
		for (OWLClass src : listClass) {
			ArrayList<OWLClassExpression> superClasses = new ArrayList<OWLClassExpression>(src.getSuperClasses(onto));
			ArrayList<OWLClassExpression> subClasses = new ArrayList<OWLClassExpression>(src.getSubClasses(onto));
			if (superClasses.isEmpty() && !subClasses.isEmpty()) {
				fathers.add(src);
			}
		}
		System.out.println(fathers.size());
		return fathers.subList(0,3);

	}

	// retirada de
	// http://stackoverflow.com/questions/5613860/issues-to-list-classes-and-subclasses-with-jena
	private static void removeClass(String inputFileName) {
		try {

			// create the reasoning model using the base
			OntModel inf = ModelFactory.createOntologyModel();

			// use the FileManager to find the input file
			InputStream in = FileManager.get().open(inputFileName);
			if (in == null) {
				throw new IllegalArgumentException("File: " + inputFileName
						+ " not found");
			}

			inf.read(in, "");

			String URI = "http://www.owl-ontologies.com/OntologyBase.owl#";

			ExtendedIterator classes = inf.listStatements();
			while (classes.hasNext()) {
				Statement essaClasse = (Statement) classes.next();

				RDFNode vClasse = essaClasse.getSubject();
				if (vClasse.isResource()) {
					System.out.println(((Resource) vClasse).getLocalName());
					inf.remove(essaClasse);
				}

				// if (essaClasse.hasSubClass()) {
				// System.out.println("Classe: " + vClasse);
				// OntClass cla = inf.getOntClass(URI + vClasse);
				// for (Iterator i = cla.listSubClasses(); i.hasNext();) {
				// OntClass c = (OntClass) i.next();
				// System.out.print("   " + c.getLocalName() + " " + "\n");
				// }
				// }
			}

			// ExtendedIterator classes2 = inf.listClasses();
			// while (classes2.hasNext()) {
			// classes2.next();
			// System.out.println("aqui");
			// }
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

	}

}
